#include "thumbnailbarwidget.h"
#include "dicomimagelabel.h"
#include "../ImageData/imageloadthread.h"
#include "../ImageData/seriesinstance.h"
#include "../ImageData/imageinstance.h"
#include "filewatcherthread.h"

#include "dcmtk/dcmdata/dcuid.h"

#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QKeyEvent>
#include <QDir>

#include <QMessageBox>

ThumbnailBarWidget::ThumbnailBarWidget(QWidget *parent) :
    currentImageLabel(0),
    QWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
    layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
    layout->setContentsMargins(6, 6, 6, 6);
    layout->addStretch();
    layout->setAlignment(Qt::AlignCenter);
}

ThumbnailBarWidget::~ThumbnailBarWidget()
{
    clear();
    emit quitFileWatcher();
}

void ThumbnailBarWidget::setCurrentImageLabel(const SeriesInstance *series)
{
    if (currentImageLabel && currentImageLabel->getSeriesInstance() == series) {
        currentImageLabel->setHighlight(true);
    } else {
        bool found = false;
        foreach (DicomImageLabel *label, imageLabelList) {
            if (series == label->getSeriesInstance()) {
                if (currentImageLabel) currentImageLabel->setHighlight(false);
                currentImageLabel = label;
                currentImageLabel->setHighlight(true);
                found = true;
                break;
            }
        }
        if ((!found) && currentImageLabel) {
            currentImageLabel->setHighlight(false);
            currentImageLabel = 0;
        }
    }
}

void ThumbnailBarWidget::firstSeries()
{
    if (!imageLabelList.isEmpty()) {
        if ((!currentImageLabel) || (currentImageLabel && currentImageLabel != imageLabelList.first()))
            onImageDoubleClicked(imageLabelList.first());
    }
}

void ThumbnailBarWidget::lastSeries()
{
    if (!imageLabelList.isEmpty()) {
        if ((!currentImageLabel) || (currentImageLabel && currentImageLabel != imageLabelList.last()))
            onImageDoubleClicked(imageLabelList.last());
    }
}

void ThumbnailBarWidget::prevSeries()
{
    if (currentImageLabel && (imageLabelList.size())) {
        int i = imageLabelList.indexOf(currentImageLabel);
        if (i > 0) {
            onImageDoubleClicked(imageLabelList.at(i-1));
        }
    }
}

void ThumbnailBarWidget::nextSeries()
{
    if (currentImageLabel && (imageLabelList.size())) {
        int i = imageLabelList.indexOf(currentImageLabel);
        if (i < imageLabelList.size()-1) {
            onImageDoubleClicked(imageLabelList.at(i+1));
        }
    }
}

void ThumbnailBarWidget::currSeries()
{
    if (currentImageLabel)
        emit imageDoubleClicked(currentImageLabel->getSeriesInstance());
}

void ThumbnailBarWidget::setFileWatcher(const QString &dir)
{
    emit quitFileWatcher();
    FileWatcherThread *t = new FileWatcherThread(dir);
    connect(this, SIGNAL(quitFileWatcher()), t, SLOT(quit()));
    connect(t, SIGNAL(finished()), t, SLOT(deleteLater()));
    connect(t, SIGNAL(filesChanged(QStringList,QStringList)),
            this, SLOT(onFilesChanged(QStringList,QStringList)));
    t->start();
}

void ThumbnailBarWidget::updateLabelImage(const SeriesInstance *series)
{
    if (currentImageLabel && currentImageLabel->getSeriesInstance()==series) {
        currentImageLabel->updateThumbnailImage();
        return;
    }

    foreach (DicomImageLabel *label, imageLabelList) {
        if (label->getSeriesInstance() == series) {
            label->updateThumbnailImage();
            break;
        }
    }
}

void ThumbnailBarWidget::appendFileFormat(DcmFileFormat *dcmff)
{
    if (dcmff) onImageReady(new ImageInstance(dcmff));
}

void ThumbnailBarWidget::appendImagePaths(const QStringList &paths, bool clearOld)
{
    QStringList pathList = paths;
    QStringList files;
    QStringList unloadedFiles;

    while (!pathList.isEmpty()) {
        QString p = pathList.takeFirst();
        QDir dir(p);
        if (dir.exists()) {
            QStringList subs = dir.entryList(QDir::Files);
            foreach (const QString &s, subs) {
                files += p + QDir::separator() + s;
            }
            subs = dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot);
            foreach (const QString &s, subs) {
                pathList += p + QDir::separator() + s;
            }
        } else {
            files += p;
        }
    }

    if (clearOld) {
        unloadedFiles = files;
        clear();
    } else {
        foreach (const QString &file, files) {
            bool found = false;
            foreach (DicomImageLabel *label, imageLabelList) {
                if (label->hasImage(file)) {
                    found = true;
                    break;
                }
            }
            if (!found) unloadedFiles << file;
        }
    }

    ImageLoadThread *thread = new ImageLoadThread(unloadedFiles);
    connect(thread, SIGNAL(resultReady(ImageInstance*)), this, SLOT(onImageReady(ImageInstance*)));
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}

void ThumbnailBarWidget::onImageReady(ImageInstance *image)
{
    bool inserted = false;
    foreach (DicomImageLabel *label, imageLabelList) {
        if (label->insertImage(image)) {
            inserted = true;
            break;
        }
    }
    if ((!inserted) && image) {
        DicomImageLabel *imageLabel = new DicomImageLabel(new SeriesInstance(image->getSeriesUid()));
        imageLabel->insertImage(image);
        connect(imageLabel, SIGNAL(imageClicked(DicomImageLabel*)),
                this, SLOT(onImageClicked(DicomImageLabel*)));
        connect(imageLabel, SIGNAL(imageDoubleClicked(DicomImageLabel*)),
                this, SLOT(onImageDoubleClicked(DicomImageLabel*)));
        layout->insertWidget(imageLabelList.size(), imageLabel);
        imageLabelList.append(imageLabel);
        if (!currentImageLabel) currentImageLabel = imageLabel;
        emit seriesInserted(imageLabel->getSeriesInstance());
    }
}

void ThumbnailBarWidget::onFilesChanged(const QStringList &removed, const QStringList &added)
{
    foreach (const QString &f, removed) {
        foreach (DicomImageLabel *l, imageLabelList) {
            if (l->removeImage(f) && l->getSeriesInstance()->isEmpty()) {
                layout->removeWidget(l);
                imageLabelList.removeOne(l);
                if (currentImageLabel == l) currentImageLabel = 0;
                l->deleteLater();
                break;
            }
        }
    }

    if ((!currentImageLabel) && (!imageLabelList.isEmpty()))
        onImageClicked(imageLabelList.first());

    appendImagePaths(added);
}

void ThumbnailBarWidget::onImageClicked(DicomImageLabel *imageLabel)
{
    if (currentImageLabel != imageLabel) {
        if (currentImageLabel) currentImageLabel->setHighlight(false);
        currentImageLabel = imageLabel;
        if (currentImageLabel) {
            currentImageLabel->setHighlight(true);
            emit currentChanged(currentImageLabel->getSeriesInstance());
        }
    }
}

void ThumbnailBarWidget::onImageDoubleClicked(DicomImageLabel *imageLabel)
{
    if (currentImageLabel) currentImageLabel->setHighlight(false);
    currentImageLabel = imageLabel;
    if (currentImageLabel) {
        currentImageLabel->setHighlight(true);
        emit imageDoubleClicked(currentImageLabel->getSeriesInstance());
    }
}

QList<SeriesInstance *> ThumbnailBarWidget::getSeriesList() const
{
    QList<SeriesInstance*> seriesList;
    foreach (DicomImageLabel *label, imageLabelList) {
        seriesList << label->getSeriesInstance();
    }
    return seriesList;
}

QSize ThumbnailBarWidget::sizeHint() const
{
    QMargins margin = layout->contentsMargins();
    int width = DicomImageLabel::getImageLabelSize();
    int height = DicomImageLabel::getImageLabelSize()*imageLabelList.size();
    if (imageLabelList.size() > 1)
        height += (imageLabelList.size()-1)*layout->spacing();

    switch (layout->direction()) {
    case QBoxLayout::TopToBottom:
    case QBoxLayout::BottomToTop:
        return QSize(width + margin.left() + margin.right(),
                     height + margin.top() + margin.bottom());
        break;
    case QBoxLayout::LeftToRight:
    case QBoxLayout::RightToLeft:
        return QSize(width + margin.top() + margin.bottom(),
                     height + margin.left() + margin.right());
        break;
    default:
        return QSize();
    }
}

void ThumbnailBarWidget::clear()
{
    qDeleteAll(imageLabelList);
    imageLabelList.clear();
    currentImageLabel = 0;
}
